{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f9444a80",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c9c1b0dd",
   "metadata": {},
   "outputs": [],
   "source": [
    "from drawdata import ScatterWidget\n",
    "import pandas as pd "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "74e1504c",
   "metadata": {},
   "outputs": [],
   "source": [
    "widget = ScatterWidget()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b6fc868e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "5c7539c904e64d789a0e5dad1c973d62",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "ScatterWidget()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widget"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1ba738f9-2331-48ec-94ee-4bbb87e7c762",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "deecd4795ccf4e619cb0ffb96a8562e6",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "BarWidget(collection_names=['usage', 'sunshine'])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from drawdata import BarWidget\n",
    "\n",
    "widget = BarWidget(collection_names=[\"usage\", \"sunshine\"], n_bins=24)\n",
    "widget"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "f027d141-9e83-401b-9a03-0aaf3f5094c6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import drawdata"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "30108537-5eb7-4d0a-9ffa-81c971443eee",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on package drawdata:\n",
      "\n",
      "NAME\n",
      "    drawdata\n",
      "\n",
      "PACKAGE CONTENTS\n",
      "\n",
      "\n",
      "CLASSES\n",
      "    anywidget.widget.AnyWidget(ipywidgets.widgets.domwidget.DOMWidget)\n",
      "        BarWidget\n",
      "        ScatterWidget\n",
      "\n",
      "    class BarWidget(anywidget.widget.AnyWidget)\n",
      "     |  BarWidget(*args: 'object', **kwargs: 'object') -> 'None'\n",
      "     |\n",
      "     |  A bar drawing widget that automatically can update a pandas/polars dataframe\n",
      "     |  as your draw data.\n",
      "     |\n",
      "     |  Method resolution order:\n",
      "     |      BarWidget\n",
      "     |      anywidget.widget.AnyWidget\n",
      "     |      ipywidgets.widgets.domwidget.DOMWidget\n",
      "     |      ipywidgets.widgets.widget.Widget\n",
      "     |      ipywidgets.widgets.widget.LoggingHasTraits\n",
      "     |      traitlets.traitlets.HasTraits\n",
      "     |      traitlets.traitlets.HasDescriptors\n",
      "     |      builtins.object\n",
      "     |\n",
      "     |  Readonly properties defined here:\n",
      "     |\n",
      "     |  data_as_pandas\n",
      "     |\n",
      "     |  data_as_polars\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors defined here:\n",
      "     |\n",
      "     |  collection_names\n",
      "     |\n",
      "     |  data\n",
      "     |\n",
      "     |  height\n",
      "     |\n",
      "     |  n_bins\n",
      "     |\n",
      "     |  width\n",
      "     |\n",
      "     |  y_max\n",
      "     |\n",
      "     |  y_min\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data and other attributes defined here:\n",
      "     |\n",
      "     |  __annotations__ = {}\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from anywidget.widget.AnyWidget:\n",
      "     |\n",
      "     |  __init__(self, *args: 'object', **kwargs: 'object') -> 'None'\n",
      "     |      Public constructor\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Class methods inherited from anywidget.widget.AnyWidget:\n",
      "     |\n",
      "     |  __init_subclass__(**kwargs: 'dict') -> 'None'\n",
      "     |      Coerces _esm and _css to FileContents if they are files.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from ipywidgets.widgets.domwidget.DOMWidget:\n",
      "     |\n",
      "     |  add_class(self, className)\n",
      "     |      Adds a class to the top level element of the widget.\n",
      "     |\n",
      "     |      Doesn't add the class if it already exists.\n",
      "     |\n",
      "     |  remove_class(self, className)\n",
      "     |      Removes a class from the top level element of the widget.\n",
      "     |\n",
      "     |      Doesn't remove the class if it doesn't exist.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from ipywidgets.widgets.domwidget.DOMWidget:\n",
      "     |\n",
      "     |  layout\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  __del__(self)\n",
      "     |      Object disposal\n",
      "     |\n",
      "     |  __repr__(self)\n",
      "     |      Return repr(self).\n",
      "     |\n",
      "     |  add_traits(self, **traits)\n",
      "     |      Dynamically add trait attributes to the Widget.\n",
      "     |\n",
      "     |  close(self)\n",
      "     |      Close method.\n",
      "     |\n",
      "     |      Closes the underlying comm.\n",
      "     |      When the comm is closed, all of the widget views are automatically\n",
      "     |      removed from the front-end.\n",
      "     |\n",
      "     |  get_state(self, key=None, drop_defaults=False)\n",
      "     |      Gets the widget state, or a piece of it.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      key : unicode or iterable (optional)\n",
      "     |          A single property's name or iterable of property names to get.\n",
      "     |\n",
      "     |      Returns\n",
      "     |      -------\n",
      "     |      state : dict of states\n",
      "     |      metadata : dict\n",
      "     |          metadata for each field: {key: metadata}\n",
      "     |\n",
      "     |  get_view_spec(self)\n",
      "     |\n",
      "     |  hold_sync(self)\n",
      "     |      Hold syncing any state until the outermost context manager exits\n",
      "     |\n",
      "     |  notify_change(self, change)\n",
      "     |      Called when a property has changed.\n",
      "     |\n",
      "     |  on_displayed(self, callback, remove=False)\n",
      "     |      (Un)Register a widget displayed callback.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      callback: method handler\n",
      "     |          Must have a signature of::\n",
      "     |\n",
      "     |              callback(widget, **kwargs)\n",
      "     |\n",
      "     |          kwargs from display are passed through without modification.\n",
      "     |      remove: bool\n",
      "     |          True if the callback should be unregistered.\n",
      "     |\n",
      "     |  on_msg(self, callback, remove=False)\n",
      "     |      (Un)Register a custom msg receive callback.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      callback: callable\n",
      "     |          callback will be passed three arguments when a message arrives::\n",
      "     |\n",
      "     |              callback(widget, content, buffers)\n",
      "     |\n",
      "     |      remove: bool\n",
      "     |          True if the callback should be unregistered.\n",
      "     |\n",
      "     |  open(self)\n",
      "     |      Open a comm to the frontend if one isn't already open.\n",
      "     |\n",
      "     |  send(self, content, buffers=None)\n",
      "     |      Sends a custom msg to the widget model in the front-end.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      content : dict\n",
      "     |          Content of the message to send.\n",
      "     |      buffers : list of binary buffers\n",
      "     |          Binary buffers to send with message\n",
      "     |\n",
      "     |  send_state(self, key=None)\n",
      "     |      Sends the widget state, or a piece of it, to the front-end, if it exists.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      key : unicode, or iterable (optional)\n",
      "     |          A single property's name or iterable of property names to sync with the front-end.\n",
      "     |\n",
      "     |  set_state(self, sync_data)\n",
      "     |      Called when a state is received from the front-end.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Class methods inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  close_all()\n",
      "     |\n",
      "     |  handle_control_comm_opened(comm, msg)\n",
      "     |      Class method, called when the comm-open message on the\n",
      "     |      \"jupyter.widget.control\" comm channel is received\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Static methods inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  get_manager_state(drop_defaults=False, widgets=None)\n",
      "     |      Returns the full state for a widget manager for embedding\n",
      "     |\n",
      "     |      :param drop_defaults: when True, it will not include default value\n",
      "     |      :param widgets: list with widgets to include in the state (or all widgets when None)\n",
      "     |      :return:\n",
      "     |\n",
      "     |  handle_comm_opened(comm, msg)\n",
      "     |      Static method, called when a widget is constructed.\n",
      "     |\n",
      "     |  on_widget_constructed(callback)\n",
      "     |      Registers a callback to be called when a widget is constructed.\n",
      "     |\n",
      "     |      The callback must have the following signature:\n",
      "     |      callback(widget)\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Readonly properties inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  model_id\n",
      "     |      Gets the model id of this widget.\n",
      "     |\n",
      "     |      If a Comm doesn't exist yet, a Comm will be created automagically.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  comm\n",
      "     |\n",
      "     |  keys\n",
      "     |      The traits which are synced.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data and other attributes inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  widget_types = <ipywidgets.widgets.widget.WidgetRegistry object>\n",
      "     |\n",
      "     |  widgets = {'5ba49ec1eeb547be95e63bac18f8dc0b': Layout(), '5c7539c904e6...\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from ipywidgets.widgets.widget.LoggingHasTraits:\n",
      "     |\n",
      "     |  log\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from traitlets.traitlets.HasTraits:\n",
      "     |\n",
      "     |  __getstate__(self) -> 'dict[str, t.Any]'\n",
      "     |      Helper for pickle.\n",
      "     |\n",
      "     |  __setstate__(self, state: 'dict[str, t.Any]') -> 'None'\n",
      "     |\n",
      "     |  has_trait(self, name: 'str') -> 'bool'\n",
      "     |      Returns True if the object has a trait with the specified name.\n",
      "     |\n",
      "     |  hold_trait_notifications(self) -> 't.Any'\n",
      "     |      Context manager for bundling trait change notifications and cross\n",
      "     |      validation.\n",
      "     |\n",
      "     |      Use this when doing multiple trait assignments (init, config), to avoid\n",
      "     |      race conditions in trait notifiers requesting other trait values.\n",
      "     |      All trait notifications will fire after all values have been assigned.\n",
      "     |\n",
      "     |  observe(self, handler: 't.Callable[..., t.Any]', names: 'Sentinel | str | t.Iterable[Sentinel | str]' = traitlets.All, type: 'Sentinel | str' = 'change') -> 'None'\n",
      "     |      Setup a handler to be called when a trait changes.\n",
      "     |\n",
      "     |      This is used to setup dynamic notifications of trait changes.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      handler : callable\n",
      "     |          A callable that is called when a trait changes. Its\n",
      "     |          signature should be ``handler(change)``, where ``change`` is a\n",
      "     |          dictionary. The change dictionary at least holds a 'type' key.\n",
      "     |          * ``type``: the type of notification.\n",
      "     |          Other keys may be passed depending on the value of 'type'. In the\n",
      "     |          case where type is 'change', we also have the following keys:\n",
      "     |          * ``owner`` : the HasTraits instance\n",
      "     |          * ``old`` : the old value of the modified trait attribute\n",
      "     |          * ``new`` : the new value of the modified trait attribute\n",
      "     |          * ``name`` : the name of the modified trait attribute.\n",
      "     |      names : list, str, All\n",
      "     |          If names is All, the handler will apply to all traits.  If a list\n",
      "     |          of str, handler will apply to all names in the list.  If a\n",
      "     |          str, the handler will apply just to that name.\n",
      "     |      type : str, All (default: 'change')\n",
      "     |          The type of notification to filter by. If equal to All, then all\n",
      "     |          notifications are passed to the observe handler.\n",
      "     |\n",
      "     |  on_trait_change(self, handler: 'EventHandler | None' = None, name: 'Sentinel | str | None' = None, remove: 'bool' = False) -> 'None'\n",
      "     |      DEPRECATED: Setup a handler to be called when a trait changes.\n",
      "     |\n",
      "     |      This is used to setup dynamic notifications of trait changes.\n",
      "     |\n",
      "     |      Static handlers can be created by creating methods on a HasTraits\n",
      "     |      subclass with the naming convention '_[traitname]_changed'.  Thus,\n",
      "     |      to create static handler for the trait 'a', create the method\n",
      "     |      _a_changed(self, name, old, new) (fewer arguments can be used, see\n",
      "     |      below).\n",
      "     |\n",
      "     |      If `remove` is True and `handler` is not specified, all change\n",
      "     |      handlers for the specified name are uninstalled.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      handler : callable, None\n",
      "     |          A callable that is called when a trait changes.  Its\n",
      "     |          signature can be handler(), handler(name), handler(name, new),\n",
      "     |          handler(name, old, new), or handler(name, old, new, self).\n",
      "     |      name : list, str, None\n",
      "     |          If None, the handler will apply to all traits.  If a list\n",
      "     |          of str, handler will apply to all names in the list.  If a\n",
      "     |          str, the handler will apply just to that name.\n",
      "     |      remove : bool\n",
      "     |          If False (the default), then install the handler.  If True\n",
      "     |          then unintall it.\n",
      "     |\n",
      "     |  set_trait(self, name: 'str', value: 't.Any') -> 'None'\n",
      "     |      Forcibly sets trait attribute, including read-only attributes.\n",
      "     |\n",
      "     |  setup_instance(*args: 't.Any', **kwargs: 't.Any') -> 'None'\n",
      "     |      This is called **before** self.__init__ is called.\n",
      "     |\n",
      "     |  trait_defaults(self, *names: 'str', **metadata: 't.Any') -> 'dict[str, t.Any] | Sentinel'\n",
      "     |      Return a trait's default value or a dictionary of them\n",
      "     |\n",
      "     |      Notes\n",
      "     |      -----\n",
      "     |      Dynamically generated default values may\n",
      "     |      depend on the current state of the object.\n",
      "     |\n",
      "     |  trait_has_value(self, name: 'str') -> 'bool'\n",
      "     |      Returns True if the specified trait has a value.\n",
      "     |\n",
      "     |      This will return false even if ``getattr`` would return a\n",
      "     |      dynamically generated default value. These default values\n",
      "     |      will be recognized as existing only after they have been\n",
      "     |      generated.\n",
      "     |\n",
      "     |      Example\n",
      "     |\n",
      "     |      .. code-block:: python\n",
      "     |\n",
      "     |          class MyClass(HasTraits):\n",
      "     |              i = Int()\n",
      "     |\n",
      "     |\n",
      "     |          mc = MyClass()\n",
      "     |          assert not mc.trait_has_value(\"i\")\n",
      "     |          mc.i  # generates a default value\n",
      "     |          assert mc.trait_has_value(\"i\")\n",
      "     |\n",
      "     |  trait_metadata(self, traitname: 'str', key: 'str', default: 't.Any' = None) -> 't.Any'\n",
      "     |      Get metadata values for trait by key.\n",
      "     |\n",
      "     |  trait_names(self, **metadata: 't.Any') -> 'list[str]'\n",
      "     |      Get a list of all the names of this class' traits.\n",
      "     |\n",
      "     |  trait_values(self, **metadata: 't.Any') -> 'dict[str, t.Any]'\n",
      "     |      A ``dict`` of trait names and their values.\n",
      "     |\n",
      "     |      The metadata kwargs allow functions to be passed in which\n",
      "     |      filter traits based on metadata values.  The functions should\n",
      "     |      take a single value as an argument and return a boolean.  If\n",
      "     |      any function returns False, then the trait is not included in\n",
      "     |      the output.  If a metadata key doesn't exist, None will be passed\n",
      "     |      to the function.\n",
      "     |\n",
      "     |      Returns\n",
      "     |      -------\n",
      "     |      A ``dict`` of trait names and their values.\n",
      "     |\n",
      "     |      Notes\n",
      "     |      -----\n",
      "     |      Trait values are retrieved via ``getattr``, any exceptions raised\n",
      "     |      by traits or the operations they may trigger will result in the\n",
      "     |      absence of a trait value in the result ``dict``.\n",
      "     |\n",
      "     |  traits(self, **metadata: 't.Any') -> 'dict[str, TraitType[t.Any, t.Any]]'\n",
      "     |      Get a ``dict`` of all the traits of this class.  The dictionary\n",
      "     |      is keyed on the name and the values are the TraitType objects.\n",
      "     |\n",
      "     |      The TraitTypes returned don't know anything about the values\n",
      "     |      that the various HasTrait's instances are holding.\n",
      "     |\n",
      "     |      The metadata kwargs allow functions to be passed in which\n",
      "     |      filter traits based on metadata values.  The functions should\n",
      "     |      take a single value as an argument and return a boolean.  If\n",
      "     |      any function returns False, then the trait is not included in\n",
      "     |      the output.  If a metadata key doesn't exist, None will be passed\n",
      "     |      to the function.\n",
      "     |\n",
      "     |  unobserve(self, handler: 't.Callable[..., t.Any]', names: 'Sentinel | str | t.Iterable[Sentinel | str]' = traitlets.All, type: 'Sentinel | str' = 'change') -> 'None'\n",
      "     |      Remove a trait change handler.\n",
      "     |\n",
      "     |      This is used to unregister handlers to trait change notifications.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      handler : callable\n",
      "     |          The callable called when a trait attribute changes.\n",
      "     |      names : list, str, All (default: All)\n",
      "     |          The names of the traits for which the specified handler should be\n",
      "     |          uninstalled. If names is All, the specified handler is uninstalled\n",
      "     |          from the list of notifiers corresponding to all changes.\n",
      "     |      type : str or All (default: 'change')\n",
      "     |          The type of notification to filter by. If All, the specified handler\n",
      "     |          is uninstalled from the list of notifiers corresponding to all types.\n",
      "     |\n",
      "     |  unobserve_all(self, name: 'str | t.Any' = traitlets.All) -> 'None'\n",
      "     |      Remove trait change handlers of any type for the specified name.\n",
      "     |      If name is not specified, removes all trait notifiers.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Class methods inherited from traitlets.traitlets.HasTraits:\n",
      "     |\n",
      "     |  class_own_trait_events(name: 'str') -> 'dict[str, EventHandler]'\n",
      "     |      Get a dict of all event handlers defined on this class, not a parent.\n",
      "     |\n",
      "     |      Works like ``event_handlers``, except for excluding traits from parents.\n",
      "     |\n",
      "     |  class_own_traits(**metadata: 't.Any') -> 'dict[str, TraitType[t.Any, t.Any]]'\n",
      "     |      Get a dict of all the traitlets defined on this class, not a parent.\n",
      "     |\n",
      "     |      Works like `class_traits`, except for excluding traits from parents.\n",
      "     |\n",
      "     |  class_trait_names(**metadata: 't.Any') -> 'list[str]'\n",
      "     |      Get a list of all the names of this class' traits.\n",
      "     |\n",
      "     |      This method is just like the :meth:`trait_names` method,\n",
      "     |      but is unbound.\n",
      "     |\n",
      "     |  class_traits(**metadata: 't.Any') -> 'dict[str, TraitType[t.Any, t.Any]]'\n",
      "     |      Get a ``dict`` of all the traits of this class.  The dictionary\n",
      "     |      is keyed on the name and the values are the TraitType objects.\n",
      "     |\n",
      "     |      This method is just like the :meth:`traits` method, but is unbound.\n",
      "     |\n",
      "     |      The TraitTypes returned don't know anything about the values\n",
      "     |      that the various HasTrait's instances are holding.\n",
      "     |\n",
      "     |      The metadata kwargs allow functions to be passed in which\n",
      "     |      filter traits based on metadata values.  The functions should\n",
      "     |      take a single value as an argument and return a boolean.  If\n",
      "     |      any function returns False, then the trait is not included in\n",
      "     |      the output.  If a metadata key doesn't exist, None will be passed\n",
      "     |      to the function.\n",
      "     |\n",
      "     |  trait_events(name: 'str | None' = None) -> 'dict[str, EventHandler]'\n",
      "     |      Get a ``dict`` of all the event handlers of this class.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      name : str (default: None)\n",
      "     |          The name of a trait of this class. If name is ``None`` then all\n",
      "     |          the event handlers of this class will be returned instead.\n",
      "     |\n",
      "     |      Returns\n",
      "     |      -------\n",
      "     |      The event handlers associated with a trait name, or all event handlers.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Readonly properties inherited from traitlets.traitlets.HasTraits:\n",
      "     |\n",
      "     |  cross_validation_lock\n",
      "     |      A contextmanager for running a block with our cross validation lock set\n",
      "     |      to True.\n",
      "     |\n",
      "     |      At the end of the block, the lock's value is restored to its value\n",
      "     |      prior to entering the block.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Static methods inherited from traitlets.traitlets.HasDescriptors:\n",
      "     |\n",
      "     |  __new__(*args: 't.Any', **kwargs: 't.Any') -> 't.Any'\n",
      "     |      Create and return a new object.  See help(type) for accurate signature.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from traitlets.traitlets.HasDescriptors:\n",
      "     |\n",
      "     |  __dict__\n",
      "     |      dictionary for instance variables\n",
      "     |\n",
      "     |  __weakref__\n",
      "     |      list of weak references to the object\n",
      "\n",
      "    class ScatterWidget(anywidget.widget.AnyWidget)\n",
      "     |  ScatterWidget(*args: 'object', **kwargs: 'object') -> 'None'\n",
      "     |\n",
      "     |  A scatter drawing widget that automatically can update a pandas/polars dataframe\n",
      "     |  as your draw data.\n",
      "     |\n",
      "     |  Method resolution order:\n",
      "     |      ScatterWidget\n",
      "     |      anywidget.widget.AnyWidget\n",
      "     |      ipywidgets.widgets.domwidget.DOMWidget\n",
      "     |      ipywidgets.widgets.widget.Widget\n",
      "     |      ipywidgets.widgets.widget.LoggingHasTraits\n",
      "     |      traitlets.traitlets.HasTraits\n",
      "     |      traitlets.traitlets.HasDescriptors\n",
      "     |      builtins.object\n",
      "     |\n",
      "     |  Readonly properties defined here:\n",
      "     |\n",
      "     |  data_as_X_y\n",
      "     |\n",
      "     |  data_as_pandas\n",
      "     |\n",
      "     |  data_as_polars\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors defined here:\n",
      "     |\n",
      "     |  brushsize\n",
      "     |\n",
      "     |  data\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data and other attributes defined here:\n",
      "     |\n",
      "     |  __annotations__ = {}\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from anywidget.widget.AnyWidget:\n",
      "     |\n",
      "     |  __init__(self, *args: 'object', **kwargs: 'object') -> 'None'\n",
      "     |      Public constructor\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Class methods inherited from anywidget.widget.AnyWidget:\n",
      "     |\n",
      "     |  __init_subclass__(**kwargs: 'dict') -> 'None'\n",
      "     |      Coerces _esm and _css to FileContents if they are files.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from ipywidgets.widgets.domwidget.DOMWidget:\n",
      "     |\n",
      "     |  add_class(self, className)\n",
      "     |      Adds a class to the top level element of the widget.\n",
      "     |\n",
      "     |      Doesn't add the class if it already exists.\n",
      "     |\n",
      "     |  remove_class(self, className)\n",
      "     |      Removes a class from the top level element of the widget.\n",
      "     |\n",
      "     |      Doesn't remove the class if it doesn't exist.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from ipywidgets.widgets.domwidget.DOMWidget:\n",
      "     |\n",
      "     |  layout\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  __del__(self)\n",
      "     |      Object disposal\n",
      "     |\n",
      "     |  __repr__(self)\n",
      "     |      Return repr(self).\n",
      "     |\n",
      "     |  add_traits(self, **traits)\n",
      "     |      Dynamically add trait attributes to the Widget.\n",
      "     |\n",
      "     |  close(self)\n",
      "     |      Close method.\n",
      "     |\n",
      "     |      Closes the underlying comm.\n",
      "     |      When the comm is closed, all of the widget views are automatically\n",
      "     |      removed from the front-end.\n",
      "     |\n",
      "     |  get_state(self, key=None, drop_defaults=False)\n",
      "     |      Gets the widget state, or a piece of it.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      key : unicode or iterable (optional)\n",
      "     |          A single property's name or iterable of property names to get.\n",
      "     |\n",
      "     |      Returns\n",
      "     |      -------\n",
      "     |      state : dict of states\n",
      "     |      metadata : dict\n",
      "     |          metadata for each field: {key: metadata}\n",
      "     |\n",
      "     |  get_view_spec(self)\n",
      "     |\n",
      "     |  hold_sync(self)\n",
      "     |      Hold syncing any state until the outermost context manager exits\n",
      "     |\n",
      "     |  notify_change(self, change)\n",
      "     |      Called when a property has changed.\n",
      "     |\n",
      "     |  on_displayed(self, callback, remove=False)\n",
      "     |      (Un)Register a widget displayed callback.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      callback: method handler\n",
      "     |          Must have a signature of::\n",
      "     |\n",
      "     |              callback(widget, **kwargs)\n",
      "     |\n",
      "     |          kwargs from display are passed through without modification.\n",
      "     |      remove: bool\n",
      "     |          True if the callback should be unregistered.\n",
      "     |\n",
      "     |  on_msg(self, callback, remove=False)\n",
      "     |      (Un)Register a custom msg receive callback.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      callback: callable\n",
      "     |          callback will be passed three arguments when a message arrives::\n",
      "     |\n",
      "     |              callback(widget, content, buffers)\n",
      "     |\n",
      "     |      remove: bool\n",
      "     |          True if the callback should be unregistered.\n",
      "     |\n",
      "     |  open(self)\n",
      "     |      Open a comm to the frontend if one isn't already open.\n",
      "     |\n",
      "     |  send(self, content, buffers=None)\n",
      "     |      Sends a custom msg to the widget model in the front-end.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      content : dict\n",
      "     |          Content of the message to send.\n",
      "     |      buffers : list of binary buffers\n",
      "     |          Binary buffers to send with message\n",
      "     |\n",
      "     |  send_state(self, key=None)\n",
      "     |      Sends the widget state, or a piece of it, to the front-end, if it exists.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      key : unicode, or iterable (optional)\n",
      "     |          A single property's name or iterable of property names to sync with the front-end.\n",
      "     |\n",
      "     |  set_state(self, sync_data)\n",
      "     |      Called when a state is received from the front-end.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Class methods inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  close_all()\n",
      "     |\n",
      "     |  handle_control_comm_opened(comm, msg)\n",
      "     |      Class method, called when the comm-open message on the\n",
      "     |      \"jupyter.widget.control\" comm channel is received\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Static methods inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  get_manager_state(drop_defaults=False, widgets=None)\n",
      "     |      Returns the full state for a widget manager for embedding\n",
      "     |\n",
      "     |      :param drop_defaults: when True, it will not include default value\n",
      "     |      :param widgets: list with widgets to include in the state (or all widgets when None)\n",
      "     |      :return:\n",
      "     |\n",
      "     |  handle_comm_opened(comm, msg)\n",
      "     |      Static method, called when a widget is constructed.\n",
      "     |\n",
      "     |  on_widget_constructed(callback)\n",
      "     |      Registers a callback to be called when a widget is constructed.\n",
      "     |\n",
      "     |      The callback must have the following signature:\n",
      "     |      callback(widget)\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Readonly properties inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  model_id\n",
      "     |      Gets the model id of this widget.\n",
      "     |\n",
      "     |      If a Comm doesn't exist yet, a Comm will be created automagically.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  comm\n",
      "     |\n",
      "     |  keys\n",
      "     |      The traits which are synced.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data and other attributes inherited from ipywidgets.widgets.widget.Widget:\n",
      "     |\n",
      "     |  widget_types = <ipywidgets.widgets.widget.WidgetRegistry object>\n",
      "     |\n",
      "     |  widgets = {'5ba49ec1eeb547be95e63bac18f8dc0b': Layout(), '5c7539c904e6...\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from ipywidgets.widgets.widget.LoggingHasTraits:\n",
      "     |\n",
      "     |  log\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from traitlets.traitlets.HasTraits:\n",
      "     |\n",
      "     |  __getstate__(self) -> 'dict[str, t.Any]'\n",
      "     |      Helper for pickle.\n",
      "     |\n",
      "     |  __setstate__(self, state: 'dict[str, t.Any]') -> 'None'\n",
      "     |\n",
      "     |  has_trait(self, name: 'str') -> 'bool'\n",
      "     |      Returns True if the object has a trait with the specified name.\n",
      "     |\n",
      "     |  hold_trait_notifications(self) -> 't.Any'\n",
      "     |      Context manager for bundling trait change notifications and cross\n",
      "     |      validation.\n",
      "     |\n",
      "     |      Use this when doing multiple trait assignments (init, config), to avoid\n",
      "     |      race conditions in trait notifiers requesting other trait values.\n",
      "     |      All trait notifications will fire after all values have been assigned.\n",
      "     |\n",
      "     |  observe(self, handler: 't.Callable[..., t.Any]', names: 'Sentinel | str | t.Iterable[Sentinel | str]' = traitlets.All, type: 'Sentinel | str' = 'change') -> 'None'\n",
      "     |      Setup a handler to be called when a trait changes.\n",
      "     |\n",
      "     |      This is used to setup dynamic notifications of trait changes.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      handler : callable\n",
      "     |          A callable that is called when a trait changes. Its\n",
      "     |          signature should be ``handler(change)``, where ``change`` is a\n",
      "     |          dictionary. The change dictionary at least holds a 'type' key.\n",
      "     |          * ``type``: the type of notification.\n",
      "     |          Other keys may be passed depending on the value of 'type'. In the\n",
      "     |          case where type is 'change', we also have the following keys:\n",
      "     |          * ``owner`` : the HasTraits instance\n",
      "     |          * ``old`` : the old value of the modified trait attribute\n",
      "     |          * ``new`` : the new value of the modified trait attribute\n",
      "     |          * ``name`` : the name of the modified trait attribute.\n",
      "     |      names : list, str, All\n",
      "     |          If names is All, the handler will apply to all traits.  If a list\n",
      "     |          of str, handler will apply to all names in the list.  If a\n",
      "     |          str, the handler will apply just to that name.\n",
      "     |      type : str, All (default: 'change')\n",
      "     |          The type of notification to filter by. If equal to All, then all\n",
      "     |          notifications are passed to the observe handler.\n",
      "     |\n",
      "     |  on_trait_change(self, handler: 'EventHandler | None' = None, name: 'Sentinel | str | None' = None, remove: 'bool' = False) -> 'None'\n",
      "     |      DEPRECATED: Setup a handler to be called when a trait changes.\n",
      "     |\n",
      "     |      This is used to setup dynamic notifications of trait changes.\n",
      "     |\n",
      "     |      Static handlers can be created by creating methods on a HasTraits\n",
      "     |      subclass with the naming convention '_[traitname]_changed'.  Thus,\n",
      "     |      to create static handler for the trait 'a', create the method\n",
      "     |      _a_changed(self, name, old, new) (fewer arguments can be used, see\n",
      "     |      below).\n",
      "     |\n",
      "     |      If `remove` is True and `handler` is not specified, all change\n",
      "     |      handlers for the specified name are uninstalled.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      handler : callable, None\n",
      "     |          A callable that is called when a trait changes.  Its\n",
      "     |          signature can be handler(), handler(name), handler(name, new),\n",
      "     |          handler(name, old, new), or handler(name, old, new, self).\n",
      "     |      name : list, str, None\n",
      "     |          If None, the handler will apply to all traits.  If a list\n",
      "     |          of str, handler will apply to all names in the list.  If a\n",
      "     |          str, the handler will apply just to that name.\n",
      "     |      remove : bool\n",
      "     |          If False (the default), then install the handler.  If True\n",
      "     |          then unintall it.\n",
      "     |\n",
      "     |  set_trait(self, name: 'str', value: 't.Any') -> 'None'\n",
      "     |      Forcibly sets trait attribute, including read-only attributes.\n",
      "     |\n",
      "     |  setup_instance(*args: 't.Any', **kwargs: 't.Any') -> 'None'\n",
      "     |      This is called **before** self.__init__ is called.\n",
      "     |\n",
      "     |  trait_defaults(self, *names: 'str', **metadata: 't.Any') -> 'dict[str, t.Any] | Sentinel'\n",
      "     |      Return a trait's default value or a dictionary of them\n",
      "     |\n",
      "     |      Notes\n",
      "     |      -----\n",
      "     |      Dynamically generated default values may\n",
      "     |      depend on the current state of the object.\n",
      "     |\n",
      "     |  trait_has_value(self, name: 'str') -> 'bool'\n",
      "     |      Returns True if the specified trait has a value.\n",
      "     |\n",
      "     |      This will return false even if ``getattr`` would return a\n",
      "     |      dynamically generated default value. These default values\n",
      "     |      will be recognized as existing only after they have been\n",
      "     |      generated.\n",
      "     |\n",
      "     |      Example\n",
      "     |\n",
      "     |      .. code-block:: python\n",
      "     |\n",
      "     |          class MyClass(HasTraits):\n",
      "     |              i = Int()\n",
      "     |\n",
      "     |\n",
      "     |          mc = MyClass()\n",
      "     |          assert not mc.trait_has_value(\"i\")\n",
      "     |          mc.i  # generates a default value\n",
      "     |          assert mc.trait_has_value(\"i\")\n",
      "     |\n",
      "     |  trait_metadata(self, traitname: 'str', key: 'str', default: 't.Any' = None) -> 't.Any'\n",
      "     |      Get metadata values for trait by key.\n",
      "     |\n",
      "     |  trait_names(self, **metadata: 't.Any') -> 'list[str]'\n",
      "     |      Get a list of all the names of this class' traits.\n",
      "     |\n",
      "     |  trait_values(self, **metadata: 't.Any') -> 'dict[str, t.Any]'\n",
      "     |      A ``dict`` of trait names and their values.\n",
      "     |\n",
      "     |      The metadata kwargs allow functions to be passed in which\n",
      "     |      filter traits based on metadata values.  The functions should\n",
      "     |      take a single value as an argument and return a boolean.  If\n",
      "     |      any function returns False, then the trait is not included in\n",
      "     |      the output.  If a metadata key doesn't exist, None will be passed\n",
      "     |      to the function.\n",
      "     |\n",
      "     |      Returns\n",
      "     |      -------\n",
      "     |      A ``dict`` of trait names and their values.\n",
      "     |\n",
      "     |      Notes\n",
      "     |      -----\n",
      "     |      Trait values are retrieved via ``getattr``, any exceptions raised\n",
      "     |      by traits or the operations they may trigger will result in the\n",
      "     |      absence of a trait value in the result ``dict``.\n",
      "     |\n",
      "     |  traits(self, **metadata: 't.Any') -> 'dict[str, TraitType[t.Any, t.Any]]'\n",
      "     |      Get a ``dict`` of all the traits of this class.  The dictionary\n",
      "     |      is keyed on the name and the values are the TraitType objects.\n",
      "     |\n",
      "     |      The TraitTypes returned don't know anything about the values\n",
      "     |      that the various HasTrait's instances are holding.\n",
      "     |\n",
      "     |      The metadata kwargs allow functions to be passed in which\n",
      "     |      filter traits based on metadata values.  The functions should\n",
      "     |      take a single value as an argument and return a boolean.  If\n",
      "     |      any function returns False, then the trait is not included in\n",
      "     |      the output.  If a metadata key doesn't exist, None will be passed\n",
      "     |      to the function.\n",
      "     |\n",
      "     |  unobserve(self, handler: 't.Callable[..., t.Any]', names: 'Sentinel | str | t.Iterable[Sentinel | str]' = traitlets.All, type: 'Sentinel | str' = 'change') -> 'None'\n",
      "     |      Remove a trait change handler.\n",
      "     |\n",
      "     |      This is used to unregister handlers to trait change notifications.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      handler : callable\n",
      "     |          The callable called when a trait attribute changes.\n",
      "     |      names : list, str, All (default: All)\n",
      "     |          The names of the traits for which the specified handler should be\n",
      "     |          uninstalled. If names is All, the specified handler is uninstalled\n",
      "     |          from the list of notifiers corresponding to all changes.\n",
      "     |      type : str or All (default: 'change')\n",
      "     |          The type of notification to filter by. If All, the specified handler\n",
      "     |          is uninstalled from the list of notifiers corresponding to all types.\n",
      "     |\n",
      "     |  unobserve_all(self, name: 'str | t.Any' = traitlets.All) -> 'None'\n",
      "     |      Remove trait change handlers of any type for the specified name.\n",
      "     |      If name is not specified, removes all trait notifiers.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Class methods inherited from traitlets.traitlets.HasTraits:\n",
      "     |\n",
      "     |  class_own_trait_events(name: 'str') -> 'dict[str, EventHandler]'\n",
      "     |      Get a dict of all event handlers defined on this class, not a parent.\n",
      "     |\n",
      "     |      Works like ``event_handlers``, except for excluding traits from parents.\n",
      "     |\n",
      "     |  class_own_traits(**metadata: 't.Any') -> 'dict[str, TraitType[t.Any, t.Any]]'\n",
      "     |      Get a dict of all the traitlets defined on this class, not a parent.\n",
      "     |\n",
      "     |      Works like `class_traits`, except for excluding traits from parents.\n",
      "     |\n",
      "     |  class_trait_names(**metadata: 't.Any') -> 'list[str]'\n",
      "     |      Get a list of all the names of this class' traits.\n",
      "     |\n",
      "     |      This method is just like the :meth:`trait_names` method,\n",
      "     |      but is unbound.\n",
      "     |\n",
      "     |  class_traits(**metadata: 't.Any') -> 'dict[str, TraitType[t.Any, t.Any]]'\n",
      "     |      Get a ``dict`` of all the traits of this class.  The dictionary\n",
      "     |      is keyed on the name and the values are the TraitType objects.\n",
      "     |\n",
      "     |      This method is just like the :meth:`traits` method, but is unbound.\n",
      "     |\n",
      "     |      The TraitTypes returned don't know anything about the values\n",
      "     |      that the various HasTrait's instances are holding.\n",
      "     |\n",
      "     |      The metadata kwargs allow functions to be passed in which\n",
      "     |      filter traits based on metadata values.  The functions should\n",
      "     |      take a single value as an argument and return a boolean.  If\n",
      "     |      any function returns False, then the trait is not included in\n",
      "     |      the output.  If a metadata key doesn't exist, None will be passed\n",
      "     |      to the function.\n",
      "     |\n",
      "     |  trait_events(name: 'str | None' = None) -> 'dict[str, EventHandler]'\n",
      "     |      Get a ``dict`` of all the event handlers of this class.\n",
      "     |\n",
      "     |      Parameters\n",
      "     |      ----------\n",
      "     |      name : str (default: None)\n",
      "     |          The name of a trait of this class. If name is ``None`` then all\n",
      "     |          the event handlers of this class will be returned instead.\n",
      "     |\n",
      "     |      Returns\n",
      "     |      -------\n",
      "     |      The event handlers associated with a trait name, or all event handlers.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Readonly properties inherited from traitlets.traitlets.HasTraits:\n",
      "     |\n",
      "     |  cross_validation_lock\n",
      "     |      A contextmanager for running a block with our cross validation lock set\n",
      "     |      to True.\n",
      "     |\n",
      "     |      At the end of the block, the lock's value is restored to its value\n",
      "     |      prior to entering the block.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Static methods inherited from traitlets.traitlets.HasDescriptors:\n",
      "     |\n",
      "     |  __new__(*args: 't.Any', **kwargs: 't.Any') -> 't.Any'\n",
      "     |      Create and return a new object.  See help(type) for accurate signature.\n",
      "     |\n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from traitlets.traitlets.HasDescriptors:\n",
      "     |\n",
      "     |  __dict__\n",
      "     |      dictionary for instance variables\n",
      "     |\n",
      "     |  __weakref__\n",
      "     |      list of weak references to the object\n",
      "\n",
      "FUNCTIONS\n",
      "    draw_histogram()\n",
      "        Deprecated histogram drawing utility that loads from an iframe\n",
      "\n",
      "    draw_line()\n",
      "        Deprecated line chart drawing utility that loads from an iframe\n",
      "\n",
      "    draw_scatter()\n",
      "        Deprecated scatter chart drawing utility that loads from an iframe\n",
      "\n",
      "FILE\n",
      "    g:\\temptest\\tempdownload\\my_env\\lib\\site-packages\\drawdata\\__init__.py\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(drawdata)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "f55ef04d-e8df-4764-a155-4c35a19592d7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAr4AAAHTCAYAAADBBRtsAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQAAV9BJREFUeJzt3Qm4U9XZ/v/FIHBAlEEEGURAKuCAlbHaglotUl4USykqagexTvSHglR9ESxURVuLM3UAxWKFWqqirQjWqQ5gmWQokwK2DCKDoIDM5H/dq+/OP+Sc5ORATnae7O/nuuIh+2TYK3fiefbKWmtXiMViMQcAAAAUuIph7wAAAACQCxS+AAAAiAQKXwAAAEQChS8AAAAigcIXAAAAkUDhCwAAgEig8AUAAEAkUPgCAAAgEih8gQhbvny5+/e//x32bsA5d+DAAffRRx+5zZs3h70rOARff/112LsAIAMUvkCEXXnlle72228/rMe466673D333HNI9/3444/dJ5984j799NNilxUrVrjVq1eXeL/PP//c/eUvf3Hr168v83Pu2rUr/u/777/fP49OYBkULuvWrXMzZ87029J59dVX/T5ky549e9w3v/lN99JLL7nysmzZMrd3796Dtr311ls+h2Rffvmlu+2229y+fftcofvVr351WFl+9dVX7oQTTnBPPPFEytvs3LnTbdu2ze3evbvU95Z+r/epMtABUToPPvigu/jii92mTZvS3k45Kn8g6ih8gQirWrWqq1KlSrHtKo527NiR0WPoj6l6jkujP/h9+vTxBWOgV69e7rTTTnOnn366O/HEE12rVq38v4PLzTffXOJjrVmzxv3whz90S5cudWV12WWX+WJd/vd//9cXfW+88Ybfj/3797tp06a5s88+223dujXt47z22mtuypQp8euVKlVyFSpUSHlR+0vLQkrKQ/dNLNgPhQ4ivvvd77oPP/zwoO1Dhw71bSmpEB87dqwbM2aMs075Dhw4MJ6BDpxUKCpjXVT0zpgxI35948aNB+U/adKkYnnqdUs8gNLj/fWvf025D/fee6876qijXLVq1VzFihXTvlf0+6KiIlerVi1/IJbOxIkT/XMfc8wxaW+ng7lzzz035cEkEBUUvkCE6Y/sU089VewPr4qvk046qVgvlAoCFUSJ9Edal+TbqocrkR6zc+fOvndKPYnyr3/9y/e0qshQj9lDDz0ULz7UO/anP/2pxP2uXLmy/3n88ceXuc133323L0LU03vEEUf4/Ro9erTr37+/L15nz57tC4TatWunfRzdL7HdKlwXLlzo2554CQqNoLBNRa970AufnIeKJe3foVKvoQ4UbrrpJvftb3+7WDv0OiSrV6+e/zbgiy++cIdLBd9vfvObQ77/3Llz/evwz3/+85Duf+yxx7rp06e7b33rW27VqlXue9/7nmvatKl//+h9t2TJEvfII4/4f+ui3w0fPjx+f73+TZo0cVu2bPEHeXqf/PSnP/W/0+Pp/TRhwgR/EDVq1KgS90GvvQ7YVHTrNdVjpbro9/o24z//+Y877rjj/P11P+3nypUr49+KqE06kNHBXPI3JtovfZui96Q+s8p90KBB/uCztB5noJD9968HgMi6/PLLfY9VIvWMJX8lrq9dVUCkMm7cuGLb9BhBkarCZfDgwe4b3/iG/4OsnmJ9/aoiQl8V6w+6is3EXlzdX79v06aNv75o0SL/Rzv4ylZFgh5L1Dumntynn376oH248MIL3R/+8Af/77Vr1/reTe3H66+/7nt41UunQkfPpcf/+9//7n7yk5/Ee/z0fPpd0PYnn3zSb9Ntt2/f7ntFdf+gnYfr97//vS9Skw8iSuoJzpT2UYW32h08pjIOivHgq/XFixe7jh07Frv/nXfeedD+XX311WV6/jp16vje/EOl+8uhPsapp57qe3QvueQSXxC+//77/v2sglbvr3POOcd169bN3Xrrrf49odfi6KOPjt9ft9FBjt5jzz//vD+A0zcUut2PfvQjn1e/fv3883Tt2tV/W3LHHXccdEChx0t8zLLS+27YsGEl/u76669Pe1+1WQW98tdQGh3sXnXVVYe8L4BpMQCR1bVr19hVV12V0W337dsXW7x4cWzFihWxVatWxS+9e/eO9e3b96Btuo1uW9pz639BpV3OOuus+H0uuuiilLe77bbbYjfccEPse9/7Xuz111/3lz59+sQuueSS+P0XLlwYO//882M9e/aMVatWzd+vS5cusYsvvthvGzNmTImP3aJFi/hj/PSnP41dfvnlsVNOOSXWsmXL2JVXXhl7+OGHY0cffXSsUqVKJV70GLt27Sr1NdbtJkyYEMu2E088MTZjxoz49c8++6xYGzt16hRbtGiR//fevXv97T799NOD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/s477/hC97zzzvOhvffee65GjRrZ2XtEYhkX2EV+9pGhfWRoHxmGI6NThmzZssVVqVLFLViwwD355JPxy1NPPeU2bdrkHnzwQff444+7Rx999LB3SOvadejQwdWuXdsNGTIko6U+Jk+e7Jo2beoaNmzoJk6ceNDvtE/169f3Y5LffPPNw94/AAAAFGDhq6ENHTt2dEuWLPHXV69e7d566y23fPlyt2LFCv9vFcR//etffS/w22+/fVg7o+fr2bOna9eunZs9e7ZbvHixGz9+fKmFcr9+/dywYcPctGnT3PDhw92yZcv873T95ptvdk888YRfc7h///5u8+bNh7WPAAAAKMAxvhqD8vzzz7s777zTj5+44IIL/OS1pUuX+t8NHjzY3X777f62us3heumll9zPfvYzt2bNGle9enU3f/58d8MNN/ihFKnceOONfn9ee+01f129zxs3bvT706tXL9egQQP32GOP+d/ddNNN7uSTT/YFcCYY41t+i3YXFRWxBJ5B5GcfGdpHhvaRYZ6O8dWA68suu8xNnz7d3XPPPb5X95FHHvHXBwwY4G9z0kkn+dUcskGFbufOnX3RK6eddprv9S3tPt27d49fVw/1yJEj47/T/if+7h//+EfKwlc9zrokvpCiIl8XCU7ZHJymORBs15idxGOJVNu1hIne7MHjJm4vaexPqu3KSI+buF2Pq9sn72Oq7blsk26v67pNMKDfepsy2V4obUrMTyetKYQ2FWJO6doUZCiF0qZ0+16IbRJ926ptJe2jxTYVYk7p2qTf6bG0P0Hha71NFUPMKfn2hz257aqrrnLHHHOM69u3r7+8++67viiVLl26uJYtW7psUKHZrFmzYi+wxhhrzG8m91Glr7PNlfa7kowaNcqNGDGi2HbNvAwm79WrV8+1aNHCrVq1yvcsBxo3buwvGgaiI46AxhZrDWQNydDRXUDr92n1Cz12YpB6XfU/NA31SNS+fXu3Z88eP846oNdG46H1fOr1DugIsm3btn78deJayzoaat26tX8N1KseyGWb9AbfunWrv532vRDaVIg5pWpTkF/dunX9gWQhtKkQc0rXJmWo5Sh1ps0vvviiINpUiDmla1PNmjV9hscdd5z77LPPCqJNhZhTujZpXpK+zU7s8bXephYh5qTbZ305s1y45ZZb/GoRo0ePjm9r0qSJmzlzpmvU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OcojQz579j+DAf72lQOt6gAcrl27dsVOOOGE2DXXXBP75JNPYt///vdjTz31VKn3W7hwYaxKlSqxJ598MrZgwYLYiSeeGFu6dGmx251//vn6v0g57T3KI78777wz1qlTp9i//vWv2Lx582L16tWLPfHEEzloTbQcSnbpcnvttddi1apVi7300kux999/P9asWbPYpk2bctSaaMp2hnz2bOeXiL992ceriax48cUXY7Vr147t2LHDX//oo49iZ511Vqn3GzhwYKxbt27x6w888EBs6NChB93mD3/4Q6x169Z8+I3ld+ONN8ZWrFgR/92VV14Zu+6668pl/6PsULJLl9tFF13k/4AHlKP+OMNOhnz2bOcX4G9f+WCoA7Ji/vz5rnPnzvGvZE477TS3ePHijO537rnnxq937NjRzZkzJ3598+bN/mujsWPHltOeo7zyu//++/1X5YFly5a5li1blsv+R9mhZJcut9I+k8j/DPns2c5P+NtXfiqX42OjAPXq1cu9/fbbxbZXqlTJXXLJJfHrFSpU8Nu2bNnixzyl8tVXX7lmzZrFr2tM2rp16+LXBw0a5Pr27evOPPPMrLYjqnKdX+Ctt97yY+BeeeWVrLQDqTPIJLt0uWWaKfI3w0R89mzmx9++8kPhizJ5/PHH3c6dO4ttf/DBB/2HPVG1atXc119/nbZwqly58kGnbAzuI2+88YZ799133cKFC7PahijLZX6BHTt2+Mk1Oj1nvXr1stIOpM4gk+zS5ZZJpsjvDAN89mzmx9++8kXhizLRTO+SNGjQwPcqJNq2bZurUqVK2serU6eO27hxY7H77Nq1y1177bW+UKtRo0aW9h65yi/RgAED3PHHH+8GDx58WPuO1BmUNbt0uWWSKfI7wwCfPXv58bev/DHGF1mhZVxmzJgRv75q1Sq3e/du/+Euy/3mzZvnGjVq5D788EO3YsUK16dPH1erVi1/Ef187733yrEl0ZTt/AJjxoxx06dP90v1VKzI/27yJbt0uZWWKfI/Q+GzZzM//vblQDlNmkPE7N271y+ZEyzh0r9//9j//M//xH+/ZcuW2L59+4rdT7Nfa9So4Zdz2bZtW+z000+P3XfffbGdO3fGVq1addBFb1f91O+Q3/nJm2++GatatWrs9ddf97/T5euvv85hq6IhXXaHktuUKVNixx13XGzNmjWx9evXxxo1ahSbPHlyjlsVLdnOkM+e3fz421f+KHyRNfqDWb169VjdunX9/wS0hmRAH1ytJ1mS//3f//XrGR511FGxdu3apfwfNMdptvLr1auXv1/ipWvXrjlrT5Skyu5Qcjtw4EDs8ssvjxUVFfmL/oBrG+xkyGfPdn7J+NuXXRX0n1z0LCMa1q9f75dk0dIudevWzfh+Wvpl7dq1rmvXrownDBH5RSu7dLnNmjXLT47S75InPsJGhsgt8rOBwhcAAACRwIh3AAAARAKFLwAAACKBwhcAAACRQOELABGlKR5aOB8AooLCFwAiSgvot27d2p8tKtlJJ53EgvkACg6FLwAYpTNz1axZ03355Zf++muvveZq167tvvrqq7T3W7JkibvyyivdwIED3VFHHeVPkdqvX7+DblO1alV/AYBCwnJmAGCYTn162WWXuZtuusl1797dXx85cmTa++zbt899/fXX7uSTT/br9ep0qDrF6qOPPupGjx7tb7N161Z35JFHusqVK/tTry5fvjxHLQKA8kOPLwAYNnToUPfII4/4hfDff/9934tbGhWzun3Lli19Qavi9+ijj3Z79+51AwYMcJs2bXKnnHKK+/vf/+5mzpxZag8yAFhB4QsAhl100UWuevXq7kc/+pG75pprMj5j1LPPPuv69Onjpk6d6l599dV4QVySihX5UwGgMPB/MwAwTKcTHjRokO/B1XCHTHzyySfuySefdBs2bHDz5s1zc+fOdS+//HLKApfCF0Ch4P9mAGDcBx984Jcm07CETJxwwgnuF7/4hatWrZof77t//34/xlceeOAB/3sV0hdeeKE7++yzy3nvASB3mNwGAIatXr3aL0l26623uhdffNHNmTOnTPe//fbb/c8777zTjRo1yhfAv/rVr9zpp5/uxo4d6ye+qfhds2ZNObUAAHKHHl8AMOw3v/mNu/jii90vf/lL99lnn8XH66ajIQ7PPfecL3BfeeUVP+yhfv36fnIbABQyCl8AMOrzzz9348aNc4MHD3ZVqlTxwxfuuuuuUu+nXt0xY8a47du3u4YNG/rCeenSpa5SpUol3v7AgQPlsPcAkHsMdQAAo9TLq6ENb7zxhr++ZcsW16RJEz9R7dxzz83oMW677TZf2N57772+B/iee+7xY38D+p1WjVi/fn25tQMAcqXktWsAACaGOSTSWdvUi1sWe/bsif9bQx00VlgFcOIKEJ06dcrC3gJA+OjxBQB4wYkqdBpjAChEFL4AAACIBCa3AQAAIBIofAEAABAJFL4AAACIBApfAAAARAKFLwAAACKBwhcAAACRQOELAACASKDwBQAAQCRQ+AIAAMBFwf8HRI8VVUrH0YAAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 设置支持中文的字体\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei']\n",
    "# 解决负号显示问题\n",
    "plt.rcParams['axes.unicode_minus'] = False\n",
    "\n",
    "class InteractivePlot:\n",
    "    def __init__(self):\n",
    "        self.fig, self.ax = plt.subplots(figsize=(8, 5))\n",
    "        self.ax.set_title(\"点击添加数据点 (按 'c' 清除画布)\")\n",
    "        self.ax.set_xlabel(\"X 轴\")\n",
    "        self.ax.set_ylabel(\"Y 轴\")\n",
    "        self.ax.grid(True, linestyle='--', alpha=0.7)\n",
    "\n",
    "        self.x_data = []\n",
    "        self.y_data = []\n",
    "        self.line, = self.ax.plot([], [], 'bo-', lw=2, label='动态折线')\n",
    "\n",
    "        self.fig.canvas.mpl_connect('button_press_event', self.on_click)\n",
    "        self.fig.canvas.mpl_connect('key_press_event', self.on_key)\n",
    "        self.ax.legend()\n",
    "\n",
    "    def on_click(self, event):\n",
    "        if event.inaxes == self.ax:\n",
    "            self.x_data.append(event.xdata)\n",
    "            self.y_data.append(event.ydata)\n",
    "            self.line.set_data(self.x_data, self.y_data)\n",
    "            self.ax.plot(event.xdata, event.ydata, 'ro', markersize=8)  # 标记点击点\n",
    "            self.fig.canvas.draw()\n",
    "            print(f\"添加点: ({event.xdata:.2f}, {event.ydata:.2f})\")\n",
    "\n",
    "    def on_key(self, event):\n",
    "        if event.key == 'c':\n",
    "            self.x_data.clear()\n",
    "            self.y_data.clear()\n",
    "            self.line.set_data([], [])\n",
    "            self.ax.clear()\n",
    "            self.ax.set_title(\"点击添加数据点 (按 'c' 清除画布)\")\n",
    "            self.ax.set_xlabel(\"X 轴\")\n",
    "            self.ax.set_ylabel(\"Y 轴\")\n",
    "            self.ax.grid(True, linestyle='--', alpha=0.7)\n",
    "            self.ax.legend()\n",
    "            self.fig.canvas.draw()\n",
    "            print(\"画布已清除\")\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    plotter = InteractivePlot()\n",
    "    plt.show()\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "e4e6d975-ee40-437a-b645-e75d66f41a04",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最终数据坐标：\n",
      "X: []\n",
      "Y: []\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.InteractiveLinePlot at 0x1b7bf194350>"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import matplotlib\n",
    "matplotlib.use('TkAgg')  # 明确指定后端\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "class InteractiveLinePlot:\n",
    "    def __init__(self):\n",
    "        self.fig, self.ax = plt.subplots()\n",
    "        self.ax.set_title(\"左键点击添加数据点（窗口关闭后数据会打印在控制台）\")\n",
    "        self.x_data = []\n",
    "        self.y_data = []\n",
    "        self.line, = self.ax.plot([], [], 'ro-', markersize=8)  # 更醒目的样式\n",
    "        self.fig.canvas.mpl_connect('button_press_event', self.on_click)\n",
    "        plt.show()\n",
    "        # 窗口关闭后显示最终数据\n",
    "        print(\"最终数据坐标：\")\n",
    "        print(\"X:\", self.x_data)\n",
    "        print(\"Y:\", self.y_data)\n",
    "\n",
    "    def on_click(self, event):\n",
    "        # 调试信息\n",
    "        print(f\"事件检测：坐标轴={event.inaxes is not None}, 按键={event.button}\")\n",
    "        \n",
    "        # 宽松条件：只要在画布内点击任何位置都接受\n",
    "        if event.inaxes is None:\n",
    "            return\n",
    "        \n",
    "        # 记录点击坐标（即使不是左键也记录）\n",
    "        x, y = event.xdata, event.ydata\n",
    "        self.x_data.append(x)\n",
    "        self.y_data.append(y)\n",
    "        \n",
    "        # 实时更新图表\n",
    "        self.line.set_data(self.x_data, self.y_data)\n",
    "        self.ax.relim()\n",
    "        self.ax.autoscale_view()\n",
    "        self.fig.canvas.draw()\n",
    "\n",
    "# 运行示例\n",
    "InteractiveLinePlot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8d061ed4-08ce-448e-a71d-448058ee2304",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 28857 (\\N{CJK UNIFIED IDEOGRAPH-70B9}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 20987 (\\N{CJK UNIFIED IDEOGRAPH-51FB}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 22270 (\\N{CJK UNIFIED IDEOGRAPH-56FE}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 34920 (\\N{CJK UNIFIED IDEOGRAPH-8868}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 28155 (\\N{CJK UNIFIED IDEOGRAPH-6DFB}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 21152 (\\N{CJK UNIFIED IDEOGRAPH-52A0}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 25240 (\\N{CJK UNIFIED IDEOGRAPH-6298}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 32447 (\\N{CJK UNIFIED IDEOGRAPH-7EBF}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 28165 (\\N{CJK UNIFIED IDEOGRAPH-6E05}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "G:\\TempTest\\TempDownload\\my_env\\Lib\\site-packages\\IPython\\core\\pylabtools.py:170: UserWarning: Glyph 38500 (\\N{CJK UNIFIED IDEOGRAPH-9664}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAG4CAYAAABvgxxbAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQAAF25JREFUeJzt3XuMVOX9+PHPAmWhFraAVSQsQgkJIl6oivXSGqPRGGJKTWxt0FBM2sTgBe1FaQON8bJqqzFao2JSalJB/aOAtcGGUMUQQUTU2lZRo4lUg2irLGBYDDu/nJMscWX9Kj/OMh92Xq9kijM7O+ehA8x7z/Occ5pqtVotAAAS6VfvAQAAfJZAAQDSESgAQDoCBQBIR6AAAOkIFAAgHYECAKQjUACAdAQKAJCOQAEA0hEoAEA6A+o9AGD//Otf/4opU6bEwIEDe/z6rl274oUXXvjC57zyyiuxc+dOz+vheePHj+/x60DvEShwkCuu9zl16tRYvXp1j1//9re//aWf43k9Pw848EzxAADpCBQAIB2BAgCkI1AAgHQECgCQjkABANIRKABAOgIFAEhHoAAA6QgUACAdgQIApCNQAIB0XCwQ+oC1a9fG17/+9R6/tn379i/9HM/7/OcBB1ZTzaU6AYCDfYrn6aefjvPPPz9GjRoVTU1NsXTp0m5fL3pn/vz5ccQRR8TgwYPj7LPPjtdff73KMQMAfdw+B8qOHTviuOOOi3vuuafHr992221x1113xX333RfPPvtsHHLIIXHuuefGzp07qxgvANAA9muKp9iDsmTJkpg+fXp5v3ipYs/Kz372s/j5z39ePrZ169Y4/PDD449//GNcdNFF1Y0cAOizKl0k+9Zbb8XmzZvLaZ0uLS0tcfLJJ8eaNWt6DJSOjo7y1qWzszP+97//xYgRI8oAAgDyK3ZSbNu2rdxR0a9fv1yBUsRJodhj8mnF/a6vfVZbW1tcf/31VQ4DAKiTTZs2xejRow/+w4znzp0b11xzzZ77xZTQmDFjyt/g0KFD6zo2AODLaW9vj9bW1hgyZEhUodJAGTlyZPnre++9Vx7F06W4f/zxx/f4Pc3NzeXts4o4ESgAcHCpanlGpWeSHTduXBkpK1eu7FZUxdE8p5xySpWbAgD6sH3eg1KcWfGNN97otjD2xRdfjOHDh5dTM3PmzIkbb7wxJkyYUAbLvHnzygUzXUf6AABUHijr16+PM888c8/9rvUjM2fOLA8l/uUvf1meK+WnP/1pfPTRR3H66afHE088EYMGDdrXTQEADSrdqe6LKaHi0ORisaw1KABwcKj689vVjAGAdAQKAJCOQAEA0hEoAEA6AgUASEegAADpCBQAIB2BAgCkI1AAgHQECgCQjkABANIRKABAOgIFAEhHoAAA6QgUACAdgQIApCNQAIB0BAoAkI5AAQDSESgAQDoCBQBIR6AAAOkIFAAgHYECAKQjUACAdAQKAJCOQAEA0hEoAEA6AgUASEegAADpCBQAIB2BAgCkI1AAgHQECgCQjkABANIRKABAOgIFAEhHoAAA6QgUACAdgQIApCNQAIB0BAoAkI5AAQDSESgAQDoCBQBIR6AAAOkIFAAgHYECAKQjUACAdAQKAJCOQAEA0hEoAEA6AgUASEegAAB9P1B2794d8+bNi3HjxsXgwYNj/PjxccMNN0StVqt6UwBAHzWg6he89dZb4957740HH3wwjj766Fi/fn3MmjUrWlpa4sorr6x6cwBAH1R5oDzzzDPxve99L6ZNm1beHzt2bCxevDjWrVtX9aYAgD6q8imeU089NVauXBmvvfZaef+ll16K1atXx3nnndfj8zs6OqK9vb3bDQBobJXvQbnuuuvKyJg4cWL079+/XJNy0003xYwZM3p8fltbW1x//fVVDwMAOIhVvgfl0UcfjYceeigWLVoUGzZsKNei/O53vyt/7cncuXNj69ate26bNm2qekgAwEGmqVbx4TWtra3lXpTZs2fveezGG2+MP/3pT/Hqq69+4fcXe1+KBbVFrAwdOrTKoQEAvaTqz+/K96B8/PHH0a9f95ctpno6Ozur3hQA0EdVvgbl/PPPL9ecjBkzpjzM+IUXXog77rgjLr300qo3BQD0UZVP8Wzbtq08UduSJUtiy5YtMWrUqPjRj34U8+fPj4EDB37h95viAYCDT9Wf35UHyv4SKABw8Em/BgUAYH8JFAAgHYECAKQjUACAdAQKAJCOQAEA0hEoAEA6AgUASEegAADpCBQAIB2BAgCkI1AAgHQECgCQjkABANIRKABAOgIFAEhHoAAA6QgUACAdgQIApCNQAIB0BAoAkI5AAQDSESgAQDoCBQBIR6AAAOkIFAAgHYECAKQjUACAdAQKAJCOQAEA0hEoAEA6AgUASEeg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AADpCBQAIB2BAgCkI1AAgHQECgCQjkABANIRKABAOgIFAEhHoAAA6QgUACAdgQIApCNQAIB0BAoAkI5AAQDSESgAQDoCBQBIR6AAAOkIFAAgHYECADROoNxzzz0xduzYGDRoUJx88smxbt263toUANDH9EqgPPLII3HNNdfEb37zm9iwYUMcd9xxce6558aWLVt6Y3MAQB/TK4Fyxx13xE9+8pOYNWtWTJo0Ke6777746le/Gn/4wx96Y3MAQB8zoOoX3LVrVzz//PMxd+7cPY/169cvzj777FizZs1ez+/o6ChvXbZu3Vr+2t7eXvXQAIBe0vW5XavVcgbKBx98ELt3747DDz+82+PF/VdffXWv57e1tcX111+/1+Otra1VDw0A6GX//e9/o6WlJV+g7KtiT0uxXqXLRx99FEceeWS8/fbblfwG2f8iLmJx06ZNMXTo0HoPp6F5L/LwXuThvcijmAEZM2ZMDB8+vJLXqzxQDj300Ojfv3+899573R4v7o8cOXKv5zc3N5e3zyrixB+2PIr3wvuRg/ciD+9FHt6LPIplHZW8TlRs4MCBccIJJ8TKlSv3PNbZ2VneP+WUU6reHADQB/XKFE8xZTNz5sw48cQTY+rUqXHnnXfGjh07yqN6AADqEig//OEP4/3334/58+fH5s2b4/jjj48nnnhir4WzPSmme4rzp/Q07cOB5/3Iw3uRh/ciD+9F330vmmpVHQ8EAFAR1+IBANIRKABAOgIFAEhHoAAA6aQLlHvuuSfGjh0bgwYNipNPPjnWrVtX7yE1nOLyAyeddFIMGTIkDjvssJg+fXps3Lix3sMiIm655ZZoamqKOXPm1HsoDeudd96Jiy++OEaMGBGDBw+OY445JtavX1/vYTWc4pIq8+bNi3HjxpXvw/jx4+OGG26o7DowfL6nn346zj///Bg1alT579HSpUu7fb14D4qjeI844ojyvSmuxff666/HQR0ojzzySHkOleIwpQ0bNsRxxx0X5557bmzZsqXeQ2soq1atitmzZ8fatWtjxYoV8cknn8Q555xTnsuG+nnuuefi/vvvj2OPPbbeQ2lYH374YZx22mnxla98JZYvXx7//ve/4/bbb49hw4bVe2gN59Zbb4177703fv/738crr7xS3r/tttvi7rvvrvfQ+rwdO3aUn8/FDoWeFO/DXXfdFffdd188++yzccghh5Sf5Tt37ty3DdUSmTp1am327Nl77u/evbs2atSoWltbW13H1ei2bNlS/EhSW7VqVb2H0rC2bdtWmzBhQm3FihW1M844o3bVVVfVe0gN6dprr62dfvrp9R4GtVpt2rRptUsvvbTbYxdccEFtxowZdRtTI4qI2pIlS/bc7+zsrI0cObL229/+ds9jH330Ua25ubm2ePHifXrtNHtQdu3aFc8//3y5K+jT5/Mv7q9Zs6auY2t0xQWgClVdAIp9V+zRmjZtWre/Hxx4jz32WHmG7AsvvLCc/pwyZUo88MAD9R5WQzr11FPLS6i89tpr5f2XXnopVq9eHeedd169h9bQ3nrrrfIErZ/+t6q4tl6xZGNfP8vrfjXjLh988EE5p/jZs80W91999dW6javRFddRKtY7FLu1J0+eXO/hNKSHH364nPIspniorzfffLOcViimon/1q1+V78mVV15ZXoOsuLwHB851111XXsl44sSJ5QVqi8+Pm266KWbMmFHvoTW0zZs3l7/29Fne9bWDLlDI+5P7P//5z/InEw684hLyV111VbkWqFg4Tv2DvdiDcvPNN5f3iz0oxd+PYq5doBxYjz76aDz00EOxaNGiOProo+PFF18sf5gqFm56L/qGNFM8hx56aFnB7733XrfHi/sjR46s27ga2eWXXx6PP/54PPnkkzF69Oh6D6chFdOexSLxb33rWzFgwIDyVixiLhagFf9d/NTIgVMclTBp0qRujx111FHx9ttv121MjeoXv/hFuRfloosuKo+kuuSSS+Lqq68uj0Kkfro+r6v4LE8TKMUu0hNOOKGcU/z0TyvF/VNOOaWuY2s0xbqnIk6WLFkSf//738vD+KiPs846K15++eXyp8OuW/ETfLEbu/jvIuo5cIqpzs8ecl+sgTjyyCPrNqZG9fHHH5frFD+t+PtQfG5QP8XnRREin/4sL6biiqN59vWzPNUUTzGvW+yaK/4Bnjp1atx5553l4UyzZs2q99Aablqn2G26bNmy8lwoXfOGxUKn4ph2Dpzi///Prv0pDtkrzsFhTdCBV/yEXizOLKZ4fvCDH5TnaVqwYEF548AqzsNRrDkZM2ZMOcXzwgsvxB133BGXXnppvYfW523fvj3eeOONbgtjix+YigMpivejmGq78cYbY8KECWWwFOerKabeinNq7ZNaMnfffXdtzJgxtYEDB5aHHa9du7beQ2o4xR+Lnm4LFy6s99Co1RxmXGd/+ctfapMnTy4Pm5w4cWJtwYIF9R5SQ2pvby//HhSfF4MGDap985vfrP3617+udXR01Htofd6TTz7Z42fEzJkz9xxqPG/evNrhhx9e/j0566yzahs3btzn7TQV/1N9XwEA/P9LswYFAKCLQAEA0hEoAEA6AgUASEegAADpCBQAIB2BAgCkI1AAgHQECgCQjkABANIRKABAOgIFAEhHoAAA6Qyo9wAA6Bs6Ozvj3XffjSFDhkRTU1O9h8MBVqvVYtu2bTFq1Kjo12//938IFAAqUcRJa2trvYdBnW3atClGjx69368jUACoRLHnpLBq1ar42te+Vu/hcIBt3749zjjjjD1/DvaXQAGgEl3TOkWcCJTG1VTR9J5FsgBAOgIFAEhHoAAA6QgUACAdgQIApCNQAIB0BAoAkI5AAQDSESgAQDoCBQBIx6nuAWAfrFu3LubPnx/Nzc17Xc156tSp8Y9//CN27dq11/d9/PHH8de//jUGDhx4AEd78BIoALAPdu7cGdOmTYsrrrii2+P/+c9/4vbbby+vRbNs2bK9vu+SSy6JWq12AEd6cDPFAwCkI1AAgHQECgCQjkABANIRKABAOgIFAEhHoAAA6QgUACAdgQIApCNQAIB0nOoeAPbBkCFD4sknnyxvn/Wd73wn2tvb44ILLujxe4vT4PPlCBQA2AdTpkyJP//5z/UeRp9nigcASEegAADpCBQAIB2BAgCkI1AAgHQECgCQjkABANIRKABAOk7UBkAlarVa+ev27dvrPRTqoOt97/pzsL8ECgCV2LZtW/nrGWecUe+hUOc/By0tLfv9Ok21qlIHgIbW2dkZ7777bnmtGtecaTy1Wq2Mk1GjRkW/fvu/gkSgAADpWCQLAKQjUACAdAQKAJCOQAEA0hEoAEA6AgUASEegAACRzf8D6bjrO31N9r0AAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from matplotlib.widgets import Button\n",
    "\n",
    "# 初始化存储坐标的列表\n",
    "x_points = []\n",
    "y_points = []\n",
    "\n",
    "# 创建图表和坐标轴\n",
    "fig, ax = plt.subplots()\n",
    "plt.subplots_adjust(bottom=0.2)  # 为按钮留出空间\n",
    "ax.set_title(\"点击图表添加折线点\")\n",
    "ax.set_xlim(0, 10)\n",
    "ax.set_ylim(0, 10)\n",
    "\n",
    "# 绘制初始空折线图\n",
    "line, = ax.plot([], [], 'bo-')\n",
    "\n",
    "# 定义点击事件处理函数\n",
    "def onclick(event):\n",
    "    if event.inaxes != ax:\n",
    "        return  # 如果点击不在坐标轴区域内则忽略\n",
    "    x, y = event.xdata, event.ydata\n",
    "    x_points.append(x)\n",
    "    y_points.append(y)\n",
    "    update_plot()\n",
    "\n",
    "# 更新折线图的函数\n",
    "def update_plot():\n",
    "    line.set_data(x_points, y_points)\n",
    "    ax.figure.canvas.draw()\n",
    "\n",
    "# 清除按钮的回调函数\n",
    "def clear_plot(event):\n",
    "    global x_points, y_points\n",
    "    x_points = []\n",
    "    y_points = []\n",
    "    update_plot()\n",
    "\n",
    "# 注册点击事件\n",
    "fig.canvas.mpl_connect('button_press_event', onclick)\n",
    "\n",
    "# 添加清除按钮\n",
    "ax_clear = plt.axes([0.7, 0.05, 0.2, 0.075])\n",
    "btn_clear = Button(ax_clear, '清除')\n",
    "btn_clear.on_clicked(clear_plot)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47290485-e564-4038-a0a1-27a725a1a7ff",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "my_env",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
